#include "common.h"
#include <time.h>

#define MAIN_FUNCTION 3

#define WINDOW1 "handpie window 1"
#define WINDOW2 "handpie window 2"
#define WINDOW3 "handpie window 3"

void mainSangin(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height);
void mainKyusik();

int main(int argc, char** argv) {

#if   MAIN_FUNCTION==4
	// OpenCV variables
	CvCapture* capture;
	IplImage* image;  // input frame
	IplImage* output1;  // output frame
	IplImage* output2;  // output frame
	IplImage* output3;  // output frame

	// Image buffers
	LPWORD imageRgb565;
	LPWORD imageHue;
	LPBYTE imageSaturation;
	LPBYTE imageIntensity;

	/*
	* temporary variables
	*/
	int resolution;
	int i, j, index;
	WORD currentHue;
	BYTE currentSat;
	BYTE currentInt;

	/*
	* running time measuring variables
	*/
	clock_t startTime = 0L;
	double elapsedTime = 0;
	char frames = 0;
	int timing = 0;

	/***************
	* main start
	***************/
	capture = cvCaptureFromCAM(0);

	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, WIDTH);
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, HEIGHT);
	cvNamedWindow(WINDOW1, CV_WINDOW_AUTOSIZE);
	cvNamedWindow(WINDOW2, CV_WINDOW_AUTOSIZE);
	cvNamedWindow(WINDOW3, CV_WINDOW_AUTOSIZE);

	if (!cvGrabFrame(capture)) {
		printf("camera is NUll");
	}
	image = cvRetrieveFrame(capture);
	output1 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
	output2 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
	output3 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);

	/*
	* memory allocation
	*/
	resolution = image->width * image->height;
	imageRgb565 = (LPWORD) malloc(sizeof(WORD) * resolution);
	imageHue = (LPWORD) malloc(sizeof(WORD) * resolution);
	imageSaturation = (LPBYTE) malloc(sizeof(BYTE) * resolution);
	imageIntensity = (LPBYTE) malloc(sizeof(BYTE) * resolution);

	/*
	* processing each frames
	*/
	while (cvWaitKey(10) < 0) {
		startTime = clock();

		cvGrabFrame(capture);
		image = cvRetrieveFrame(capture);

		// convert rgb to hsi
		//rgb888to565((LPBYTE) image->imageData, imageRgb565, image->width, image->height);
		//rgb2hsi(imageRgb565, imageHue, imageSaturation, imageIntensity, image->width, image->height);
		rgb888toHsi((LPBYTE) image->imageData, imageHue, imageSaturation, imageIntensity, image->width, image->height);
#endif 

#if   MAIN_FUNCTION==0
#elif MAIN_FUNCTION==1
#elif MAIN_FUNCTION==2
#elif MAIN_FUNCTION==3
		mainKyusik();
#elif MAIN_FUNCTION==4
		mainSangin((LPBYTE) image->imageData, imageHue, imageSaturation, imageIntensity, image->width, image->height);
#endif	


#if   MAIN_FUNCTION==4
		// 여기에 자신의 mainName() 함수를 사용하면 됨
		output2->imageData = (char*)imageHue;
		output3->imageData = (char*)imageSaturation;

		cvShowImage(WINDOW1, image);
		cvShowImage(WINDOW2, output2);
		cvShowImage(WINDOW3, output3);

		// fps 계산
		frames++;
		elapsedTime = (elapsedTime + ((double) (clock() - startTime) / CLOCKS_PER_SEC));
		if (elapsedTime >= 1.0) {
			printf("fps: %d\n", frames);
			elapsedTime -= 1.0;
			frames = 0;
		}
	}

	/*
	* release allocation & resources
	*/
	free(imageRgb565);
	free(imageHue);
	free(imageSaturation);
	free(imageIntensity);
	cvReleaseImage(&output1);
	cvReleaseImage(&output2);
	cvReleaseImage(&output3);
	cvReleaseCapture(&capture);
	cvDestroyWindow(WINDOW1);
	cvDestroyWindow(WINDOW2);
	cvDestroyWindow(WINDOW3);
#endif
	return 0;

}

void mainSangin(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height) {
}

void mainKyusik() {
	int R, G, B, i, j;
	int x1, x2, y1, y2;
	int x, y;
	coordinate_t point;
	areaCoordinate_t interestedArea;
	int range, r;
	int startAndEnd = 0;
	pthread_t tid[50];
	argumentDataSet_t* argumentsData[30];


	//memory allocation for thread arguments
	for (int i = 0; i < 30; i++)
	{
		argumentsData[i] = (argumentDataSet_t*) malloc(sizeof(argumentDataSet_t));
	}

	IplImage *image;
	CvCapture *capture;

	IplImage *image_binary;
	capture = cvCaptureFromCAM(0);
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, WIDTH);
	cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, HEIGHT);

	if (!cvGrabFrame(capture)) {
		printf("camera is NUll");
	}
	cvNamedWindow("camera", 0);
	cvResizeWindow("camera", 640, 480);

	//binarization
	while (cvWaitKey(10) < 0) {
		cvGrabFrame(capture);
		image = cvRetrieveFrame(capture);
		image_binary = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 3);
		//printf("getsizs : %d, ipl: %d\n", cvGetSize(image), IPL_DEPTH_8U);

		x1 = 9999;
		x2 = 0;
		y1 = 9999;
		y2 = 0;
		for (i = 0; i < HEIGHT; i++) {
			for (j = 0; j < WIDTH; j++) {
				int temp = (i*WIDTH + j) * 3;
				R = image->imageData[temp + 2];
				G = image->imageData[temp + 1];
				B = image->imageData[temp + 0];


				if (R> 95 && G >40 && B > 20 &&
					MAX_(R, MAX_(G, B)) - MIN_(R, MIN_(G, B)) > 15 &&
					ABS(R, G) > 15 && R > G && R > B) {
					image_binary->imageData[temp + 2] = 255;
					image_binary->imageData[temp + 1] = 255;
					image_binary->imageData[temp] = 255;
				}
				else {
					image_binary->imageData[temp + 2] = 0;
					image_binary->imageData[temp + 1] = 0;
					image_binary->imageData[temp] = 0;
				}

			}

		}

		//erode
		erodeImage(image_binary);

		for (i = 0; i < HEIGHT; i++) {
			for (j = 0; j < WIDTH; j++) {
				int temp = (i*WIDTH + j) * 3;
				if (image_binary->imageData[temp] == 255) {
					x1 = MIN_(j, x1);
					x2 = MAX_(j, x2);
					y1 = MIN_(i, y1);
					y2 = MAX_(i, y2);
				}
			}
		}


		//draw the area of hand
		cvRectangle(image_binary,
					cvPoint(x1, y1),
					cvPoint(x2, y2),
					CV_RGB(255, 0, 0), 5, 8, 0);
		//printf("%d %d %d %d", x1, y1, x2-x1, y2-y1);


				
		interestedArea.point1.x = x1;
		interestedArea.point1.y = y1;
		interestedArea.point2.x = x2;
		interestedArea.point2.y = y2;

		//find image_binary's center of gravity and return that to point
		findCentre(image_binary, point, interestedArea);

		//printf("%d %d\n", point.x, point.y);

		//draw circle point of center of gravity
		cvCircle(image_binary, cvPoint(point.x, point.y), 10, CV_RGB(0, 255, 0), -1);
		

		//start threads
		for (int i = 0; i < 6; i++)
		{
			setArguments(argumentsData[i], image_binary, interestedArea, point, 0.3 + i * 0.05);
			pthread_create(&tid[i], NULL, detectFinger, (void*) argumentsData[i]);
		}

		
		for (int i = 0; i < 6; i++)
		{
			pthread_join(tid[i], NULL);
		}
		

		//printf("------------\n");
		//getchar();
		cvShowImage("camera", image_binary);
		cvReleaseImage(&image_binary);
	}

	cvReleaseCapture(&capture);
	cvDestroyWindow("camera");
	return;
}
